﻿using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Threading;
using DotNetNuke.Entities.Users;
using DNNSec = DotNetNuke.Security.Membership;
using DotNetNuke.Entities.Modules;
using DotNetNuke.Security.Permissions;
using DotNetNuke.Entities.Portals;
using System.Collections;


namespace DotNetNuke.Modules.AjaxWebLinks.Components
{
    public class AjaxSecurityContext
    {
        public const string SYSTEM_PERM_EDIT = "EDIT";
        public const string SYSTEM_PERM_VIEW = "VIEW";
        /// <summary>
        /// I throw an exception if I can't find the portalId!
        /// Must verify module name is teh same as current
        /// Important to use data checks to enforce multiple module instance security
        /// </summary>
        /// <param name="context"></param>
        public AjaxSecurityContext(HttpContext context)
        {
            //Get ModuleId from header
            int moduleId = int.Parse(context.Request.Headers["x-dnn-moduleid"]);

            //Get tabId from header
            this.tabId = int.Parse(context.Request.Headers["x-dnn-tabid"]);

            //Get portalid from context url
            setPortalId(context);

            //We were not able to get portal id..sorry
            if (this.portalId == -1)
            {
                throw new Exception("Cannot find portal for this URL " + context.Request.Url.AbsoluteUri);
            }

            //Get current user given portal
            userInfo = getCurrentUser(portalId);

            //Get current module info from supplied info
            moduleInfo = getModuleInfo(moduleId, tabId);

            //Sorry but the module either does not exist or you do not have access to it
            if (moduleInfo == null || !ModuleFolderInUrl(context.Request.Url) || !canView)
            {
                throw new Exception("Cannot complete this action for moduleid:" + moduleId);
            }
        }




        #region Static methods... you want 'em you got 'em

        /// this method works when DotNetNuke.Entities.Users.UserController.GetCurrentUserInfo(); does not
        /// because we only need the portalId to make it work
        /// <returns>null if there is no current user</returns>
        public static UserInfo getCurrentUser(int portalId)
        {
            if (!Thread.CurrentPrincipal.Identity.IsAuthenticated)
                return null;
            DNNSec.MembershipProvider memProvider = DNNSec.MembershipProvider.Instance();
            UserInfo retVal = memProvider.GetUserByUserName(portalId, Thread.CurrentPrincipal.Identity.Name);
            return retVal;
        }

        public static ModuleInfo getModuleInfo(int moduleId, int tabId)
        {
            ModuleController modController = new ModuleController();
            ModuleInfo modInfo = modController.GetModule(moduleId, tabId);
            return modInfo;

        }

        /// <param name="moduleId"></param>
        /// <param name="tabId"></param>
        /// <param name="permissionKey">You can use the constants, but for modules there are only
        /// those two</param>
        /// <returns></returns>
        public static bool canUserAccessModule(UserInfo user, int portalId, int tabId, ModuleInfo moduleInfo, string permissionKey)
        {
            bool retVal = false;
            string permissionsString = null;
            if (moduleInfo.InheritViewPermissions)
            {
                TabPermissionCollection tabPermissionCollection = TabPermissionController.GetTabPermissions(tabId, portalId);
                permissionsString = tabPermissionCollection.ToString(permissionKey);
            }
            else
            {
                ModulePermissionCollection permissionCollection = ModulePermissionController.GetModulePermissions(moduleInfo.ModuleID, tabId);
                permissionsString = permissionCollection.ToString(permissionKey);
            }


            char[] splitter = { ';' };
            string[] roles = permissionsString.Split(splitter);
            foreach (string role in roles)
            {
                if (role.Length > 0)
                {
                    if (user != null && user.IsInRole(role))
                        retVal = true;
                    else if (user == null && role.ToLower().Equals("all users"))
                        retVal = true;
                }

            }
            return retVal;

        }


        /// <summary>
        /// returns the portalId or -1 if something goes wrong
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public static int getPortalId(HttpContext context)
        {
            int retVal = -1;
            string url = getUriWithoutProtocol(context.Request.Url);
            PortalAliasController controller = new PortalAliasController();
            PortalAliasCollection aliasCollection = controller.GetPortalAliases();
            foreach (string key in aliasCollection.Keys)
            {
                PortalAliasInfo info = aliasCollection[key] as PortalAliasInfo;
                if (url.StartsWith(info.HTTPAlias))
                    retVal = info.PortalID;
            }
            return retVal;
        }

        /// <summary>
        /// pass me the Request.Url
        /// </summary>
        /// <param name="uri"></param>
        /// <returns></returns>
        static string getUriWithoutProtocol(Uri uri)
        {
            string protocol = uri.Scheme;
            string retVal = uri.AbsoluteUri;
            retVal = retVal.Substring(protocol.Length + 3); // strip off the //:
            return retVal;
        }
        #endregion static methods


        int _portalId;
        UserInfo _userInfo;
        ModuleInfo _moduleInfo;
        int _tabId;



        #region accessors, boring...

        public int tabId
        {
            get { return _tabId; }
            set { _tabId = value; }
        }

        public ModuleInfo moduleInfo
        {
            get { return _moduleInfo; }
            set { _moduleInfo = value; }
        }
        public int portalId
        {
            get { return _portalId; }
            set { _portalId = value; }
        }

        public UserInfo userInfo
        {
            get { return _userInfo; }
            set { _userInfo = value; }
        }


        #endregion accessors





        public bool HasPerm(string permissionKey)
        {
            if (moduleInfo == null)
                return false; // userInfo can be null if we're not logged in
            return canUserAccessModule(userInfo, portalId, tabId, moduleInfo, permissionKey);
        }

        //wrapper for edit permissions
        public bool canEdit
        {
            get
            {
                return HasPerm(SYSTEM_PERM_EDIT);
            }
        }

        //Wrapper for view permissions
        public bool canView
        {
            get
            {
                return HasPerm(SYSTEM_PERM_VIEW);
            }
        }

        /// <summary>
        /// returns true if the modueInfo loaded from client supplied moduleId has a folderName
        /// that matches url of current request
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public bool ModuleFolderInUrl(Uri uri)
        {
            //Build a string we should find in absolute path if we are making call from the right module
            string DesktopModulePath = "/DesktopModules/" + moduleInfo.DesktopModule.FolderName + "/";
            //Get the absolute path from uri
            string RequestPath = uri.AbsolutePath.ToLower();

            return RequestPath.Contains(DesktopModulePath.ToLower());
            
        }

        /// <summary>
        /// returns the portalId or -1 if something goes wrong
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public void setPortalId(HttpContext context)
        {
            portalId = -1;


            string url = getUriWithoutProtocol(context.Request.Url);
            PortalAliasController controller = new PortalAliasController();
            PortalAliasCollection aliasCollection = controller.GetPortalAliases();
            foreach (string key in aliasCollection.Keys)
            {
                PortalAliasInfo info = aliasCollection[key] as PortalAliasInfo;
                if (url.StartsWith(info.HTTPAlias, StringComparison.CurrentCultureIgnoreCase))
                {
                    portalId = info.PortalID;

                }
            }
        }
    }
}
